package com.bakerj.infinitecards.slice;

import com.bakerj.infinitecards.AnimationTransformer;
import com.bakerj.infinitecards.InfiniteCardView;
import com.bakerj.infinitecards.ResourceTable;
import com.bakerj.infinitecards.Util.ComponentStatusCheckingUtil;
import com.bakerj.infinitecards.Util.ListCheckingUtil;
import com.bakerj.infinitecards.ZIndexTransformer;
import com.bakerj.infinitecards.CardItem;
import com.bakerj.infinitecards.transformer.DefaultCommonTransformer;
import com.bakerj.infinitecards.transformer.DefaultTransformerToBack;
import com.bakerj.infinitecards.transformer.DefaultTransformerToFront;
import com.bakerj.infinitecards.transformer.LinearInterpolator;
import com.bakerj.infinitecards.transformer.DefaultZIndexTransformerCommon;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;

import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.global.resource.NotExistException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * MainAbilitySlice
 *
 * @author BakerJ
 * @since : 2021.5.24
 */
public class MainAbilitySlice extends AbilitySlice {
    private static final int CANCEL = 0;

    private InfiniteCardView mCardView;
    private BaseItemProvider mAdapter1;
    private BaseItemProvider mAdapter2;
    private Button myDialog;
    private MyEventHandler myHandler;
    private EventRunner runner;
    private InnerEvent event;
    private ComponentStatusCheckingUtil componentStatusCheckingUtil;

    private int[] resId = {ResourceTable.Media_pic1, ResourceTable.Media_pic2,
            ResourceTable.Media_pic3, ResourceTable.Media_pic4, ResourceTable.Media_pic5};

    private boolean mIsAdapter1 = true;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        if (this.findComponentById(ResourceTable.Id_view) instanceof InfiniteCardView) {
            mCardView = (InfiniteCardView) this.findComponentById(ResourceTable.Id_view);
        }
        mAdapter1 = new MyAdapter(resId, this);
        mAdapter2 = new MyAdapter(resId, this);
        mCardView.setAdapter(mAdapter1);
        if (findComponentById(ResourceTable.Id_myDialog) instanceof Button) {
            myDialog = (Button) findComponentById(ResourceTable.Id_myDialog);
        }
        componentStatusCheckingUtil = new ComponentStatusCheckingUtil();
        mCardView.setCardAnimationListener(new InfiniteCardView.CardAnimationListener() {
            @Override
            public void onAnimationStart() {
                myDialog.setVisibility(Component.VISIBLE);
                myDialog.setText("Animation Start");
            }

            @Override
            public void onAnimationEnd() {
                myDialog.setText("Animation End");
                sendHandler();
            }
        });
        initButton();
    }

    private void initButton() {
        findComponentById(ResourceTable.Id_pre).setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (componentStatusCheckingUtil.componentStatusCheck(myDialog) == "COMPONENT_HIDE") {
                    if (mIsAdapter1) {
                        setStyle2();
                        mCardView.bringCardToFront(mAdapter1.getCount() - 1);
                    } else {
                        setStyle1();
                        mCardView.bringCardToFront(mAdapter2.getCount() - 1);
                    }
                }
            }
        });
        findComponentById(ResourceTable.Id_change).setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (componentStatusCheckingUtil.componentStatusCheck(myDialog) == "COMPONENT_HIDE") {
                    if (mCardView.isAnimating()) {
                        return;
                    }
                    mIsAdapter1 = !mIsAdapter1;
                    if (mIsAdapter1) {
                        setStyle2();
                        mCardView.setAdapter(mAdapter1);
                    } else {
                        setStyle1();
                        mCardView.setAdapter(mAdapter2);
                    }
                }
            }
        });
        findComponentById(ResourceTable.Id_next).setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (componentStatusCheckingUtil.componentStatusCheck(myDialog) == "COMPONENT_HIDE") {
                    if (mIsAdapter1) {
                        setStyle2();
                    } else {
                        setStyle3();
                    }
                    mCardView.bringCardToFront(1);
                }
            }
        });
    }

    private void setStyle1() {
        mCardView.setClickable(true);
        mCardView.setAnimType(InfiniteCardView.ANIM_TYPE_FRONT);
        mCardView.setAnimInterpolator(new LinearInterpolator());
        mCardView.setTransformerToFront(new DefaultTransformerToFront());
        mCardView.setTransformerToBack(new DefaultTransformerToBack());
        mCardView.setZIndexTransformerToBack(new DefaultZIndexTransformerCommon());
    }

    private void setStyle2() {
        mCardView.setClickable(true);
        mCardView.setAnimType(InfiniteCardView.ANIM_TYPE_SWITCH);
        mCardView.setAnimInterpolator(input -> {
            input -= 1.0f;
            return input * input * ((-18 + 1) * input + -18) + 1.0f;
        });
        mCardView.setTransformerToFront(new DefaultTransformerToFront());
        mCardView.setTransformerToBack(new AnimationTransformer() {
            @Override
            public void transformAnimation(Component view, float fraction, int cardWidth,
                                           int cardHeight, int fromPosition, int toPosition) {
                int positionCount = fromPosition - toPosition;
                float scale = (float) ((0.8F - 0.1F * (double) fromPosition)
                        + (0.1F * (double) fraction * (double) positionCount));
                view.setScaleX(scale);
                view.setScaleY(scale);
                if (fraction < 0.5) {
                    view.setRotation(180 * fraction);
                } else {
                    view.setRotation((float) (180 * (1 - (double) fraction)));
                }
            }

            @Override
            public void transformInterpolatedAnimation(Component view, float fraction, int cardWidth,
                                                       int cardHeight, int fromPosition, int toPosition) {
                int positionCount = fromPosition - toPosition;
                float scale = (float) ((0.8F - 0.1F * (double) fromPosition)
                        + (0.1F * (double) fraction * (double) positionCount));
                view.setTranslationY((float) ((double) (-cardHeight)
                        * (0.8F - (double) scale) * 0.5F - (double) cardWidth * (0.02F *
                        (double) fromPosition - 0.02F * (double) fraction * (double) positionCount)));
            }
        });
        mCardView.setZIndexTransformerToBack(new ZIndexTransformer() {
            @Override
            public void transformAnimation(CardItem card, float fraction, int cardWidth,
                                           int cardHeight, int fromPosition, int toPosition) {
                if (fraction < 0.4f) {
                    card.zIndex = (float) (1f + 0.01f * (double) fromPosition);
                } else {
                    card.zIndex = (float) (1f + 0.01f * (double) toPosition);
                }
            }

            @Override
            public void transformInterpolatedAnimation(CardItem card, float fraction,
                                                       int cardWidth, int cardHeight, int fromPosition, int toPosition) {
            }
        });
    }

    private void setStyle3() {
        mCardView.setClickable(false);
        mCardView.setAnimType(InfiniteCardView.ANIM_TYPE_FRONT_TO_LAST);
        mCardView.setAnimInterpolator(input -> {
            input -= 1.0f;
            return input * input * ((-8 + 1) * input + -8) + 1.0f;
        });
        mCardView.setTransformerToFront(new DefaultCommonTransformer());
        mCardView.setTransformerToBack(new AnimationTransformer() {
            @Override
            public void transformAnimation(Component view, float fraction, int cardWidth,
                                           int cardHeight, int fromPosition, int toPosition) {
                int positionCount = fromPosition - toPosition;
                float scale = (float) ((0.8F - 0.1F * (double) fromPosition) +
                        (0.1F * (double) fraction * (double) positionCount));
                view.setScaleX(scale);
                view.setScaleY(scale);
                if (fraction < 0.5) {
                    view.setTranslationX(cardWidth * fraction * 1.5f);
                    view.setRotation(-45 * fraction);
                } else {
                    view.setTranslationX((float) ((double) cardWidth * 1.5F * (1F - (double) fraction)));
                    view.setRotation((float) (-45 * (1 - (double) fraction)));
                }
            }

            @Override
            public void transformInterpolatedAnimation(Component view, float fraction, int cardWidth,
                                                       int cardHeight, int fromPosition, int toPosition) {
                int positionCount = fromPosition - toPosition;
                float scale = (float) ((0.8F - 0.1F * (double) fromPosition) +
                        (0.1F * (double) fraction * (double) positionCount));
                view.setTranslationY((float) ((double) (-cardHeight) * (0.8f - (double) scale)
                        * 0.5f - (double) cardWidth * (0.02f *
                        (double) fromPosition - 0.02f * (double) fraction * (double) positionCount)));
            }
        });
        mCardView.setZIndexTransformerToBack(new ZIndexTransformer() {
            @Override
            public void transformAnimation(CardItem card, float fraction, int cardWidth, int cardHeight,
                                           int fromPosition, int toPosition) {
                if (fraction < 0.5f) {
                    card.zIndex = (float) (1f + 0.01f * (double) fromPosition);
                } else {
                    card.zIndex = (float) (1f + 0.01f * (double) toPosition);
                }
            }

            @Override
            public void transformInterpolatedAnimation(CardItem card, float fraction, int cardWidth,
                                                       int cardHeight, int fromPosition, int toPosition) {
            }
        });
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    private static class MyAdapter extends BaseItemProvider {
        private int[] resIds;
        private List<PixelMapElement> myList;
        private Component myComponent;

        MyAdapter(int[] resIds, Context context) {
            this.resIds = resIds;
            ListCheckingUtil listCheckingUtil = new ListCheckingUtil();
            myList = new ArrayList<>(resIds.length);
            if (!listCheckingUtil.listIsNull(myList)) {
                for (int i = 0; i < resIds.length; i++) {
                    try {
                        PixelMapElement pixelMapElement =
                                new PixelMapElement(context.getResourceManager().getResource(resIds[i]));
                        myList.add(pixelMapElement);
                    } catch (IOException | NotExistException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        @Override
        public int getCount() {
            return resIds.length;
        }

        @Override
        public Integer getItem(int position) {
            return resIds[position];
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
            myComponent = component;
            if (myComponent == null) {
                myComponent = LayoutScatter
                        .getInstance(componentContainer.getContext())
                        .parse(ResourceTable.Layout_item_card, componentContainer, false);
            }
            myComponent.setBackground(myList.get(i));
            return myComponent;
        }
    }

    private class MyEventHandler extends EventHandler {
        private MyEventHandler(EventRunner runner) {
            super(runner);
        }

        // 重写实现processEvent方法
        @Override
        public void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event == null) {
                return;
            }
            int eventId = event.eventId;
            switch (eventId) {
                case CANCEL:
                    Object object = event.object;
                    if (object instanceof EventRunner) {
                        // 将原先线程的EventRunner实例投递给新创建的线程
                        EventRunner runner2 = (EventRunner) object;
                        // 将原先线程的EventRunner实例与新创建的线程的EventHandler绑定
                        EventHandler myHandler2 = new EventHandler(runner2) {
                            @Override
                            public void processEvent(InnerEvent event) {
                                myDialog.setVisibility(Component.HIDE);
                            }
                        };
                        int eventId2 = 2;
                        long param2 = 0L;
                        Object object2 = null;
                        InnerEvent event2 = InnerEvent.get(eventId2, param2, object2);
                        myHandler2.sendEvent(event2); // 投递事件到原先的线程
                    }
                    break;
                default:
                    break;
            }
        }
    }

    private void sendHandler() {
        if (runner != null && myHandler != null) {
            // 取消掉上一次发送的事件
            myHandler.removeAllEvent();
        } else {
            runner = EventRunner.create(true); // create()的参数是true时，则为托管模式
            myHandler = new MyEventHandler(runner);
        }
        long param = 0L;
        event = InnerEvent.get(CANCEL, param, EventRunner.current());
        myHandler.removeAllEvent();
        myHandler.sendEvent(event, 300);
    }

}
